#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest/doctest.h"
#include "klib/utils.hpp"
#include "klib_http/url_enc_dec.hpp"

using namespace klib;
using namespace klib::http;

template<typename... Args>
requires (sizeof...(Args) % 2 == 0 && (std::is_same_v<cp_char_t, std::decay_t<Args>> && ...))
void check_url_params(string_view text, bool is_query, bool is_valid, size_t count, Args... args) {

    cp_char_t arr[sizeof...(Args)] { args... };
    url_params_t u(text, is_query);

    DOCTEST_INFO("1text = ", text, ", is_query = ", is_query, ", is_valid = ", is_valid);

    if (!u.is_valid())
        return;

    size_t u_count = 0;
    bool foreach_ret = true;

    u.foreach([&u_count, &arr, &foreach_ret] (string_view k, string_view v) {
        foreach_ret = false;
        size_t idx = u_count * 2;

        if (idx < sizeof...(args)) {
            string_view sk(arr[idx]), sv(arr[idx + 1]);
            DOCTEST_CHECK(sk == k);
            DOCTEST_CHECK(sv == v);
        }

        u_count++;
        return foreach_ret = true;
    });

    if (!foreach_ret) return;

    DOCTEST_CHECK(count == u_count);
}

void check_enc(string_view text, string_view expect) {
    string s = url_encode(text);
    DOCTEST_CHECK(s == expect);
    DOCTEST_INFO("text = ", text, ", s = ", s, ", expect = ", expect);
}

void check_enc_component(string_view text, string_view expect) {
    string s = url_encode_component(text);
    DOCTEST_CHECK(s == expect);
    DOCTEST_INFO("text = ", text, ", s = ", s, ", expect = ", expect);
}

void check_dec(string_view text, string_view expect) {
    string s = url_decode(text);
    DOCTEST_INFO("text = ", text, ", decode = ", s, ", expect = ", expect);
    DOCTEST_CHECK(s == expect);
}

TEST_CASE("url decode") {
    check_url_params("", true, false, 0);
    check_url_params("", false, false, 0);
    check_url_params("a=3&b=BB&CC=c&d=5", false, false, 0);
    check_url_params("a=3&b=BB&CC=c&d=5", true, true, 4, "a", "3", "b", "BB", "CC", "c");
    check_url_params("a=&b=BB&CC=c&d=5", true, true, 3, "b", "BB", "CC", "c");
    check_url_params("a&b=BB&CC=c&d=5", true, true, 3, "b", "BB", "CC", "c");
    check_url_params("=a&b=BB&CC=c&d=5", true, true, 3, "b", "BB", "CC", "c");
    check_url_params("/get?a=3&b=BB&CC=c&d=5", false, true, 4, "a", "3", "b", "BB", "CC", "c");
    check_url_params("/get?a=3&b=BB&CC=c&d=5", true, true, 4, "/get?a", "3", "b", "BB", "CC", "c");
    check_url_params("/get?c=中国&城市=北京", false, true, 2, "c", "中国", "城市", "北京");

    check_dec("http%3A%2F%2Fa.com%3Fc%3D1%26d%3D2", "http://a.com?c=1&d=2");
    check_dec("%E4%B8%AD%E5%9B%BD%2F-%E5%8C%97%E4%BA%AC", "中国/-北京");
}

TEST_CASE("url encode") {
    check_enc("http:://a.com/get?c= ^a&城市=北京", "http:://a.com/get?c=%20%5Ea&城市=北京");
    check_enc_component("http://a.com?c=1&d=2", "http%3A%2F%2Fa.com%3Fc%3D1%26d%3D2");
}